package com.stars.easyms.datasource.pagehelper;

import com.github.pagehelper.Dialect;
import com.github.pagehelper.dialect.AbstractHelperDialect;
import com.github.pagehelper.dialect.helper.*;
import com.github.pagehelper.page.PageAutoDialect;
import com.stars.easyms.datasource.EasyMsDataSource;
import com.stars.easyms.datasource.common.EasyMsDataSourceConstant;
import com.stars.easyms.datasource.exception.PageHelperException;
import com.stars.easyms.datasource.pagehelper.dialect.EasyMsOracleDialect;

import java.util.HashMap;
import java.util.Map;
import java.util.Properties;
import java.util.concurrent.ConcurrentHashMap;

/**
 * <p>className: EasyMsPageAutoDialect</p>
 * <p>description: EasyMs自定义自动PageAutoDialect类</p>
 *
 * @author guoguifang
 * @date 2019-11-25 14:59
 * @see PageAutoDialect
 * @since 1.4.1
 */
final class EasyMsPageAutoDialect {

    private static Map<String, Class<? extends Dialect>> dialectAliasMap = new HashMap<>();

    private static void registerDialectAlias(String alias, Class<? extends Dialect> dialectClass) {
        dialectAliasMap.put(alias, dialectClass);
    }

    static {
        //注册别名
        registerDialectAlias("hsqldb", HsqldbDialect.class);
        registerDialectAlias("h2", HsqldbDialect.class);
        registerDialectAlias("postgresql", HsqldbDialect.class);
        registerDialectAlias("phoenix", HsqldbDialect.class);
        registerDialectAlias("mysql", MySqlDialect.class);
        registerDialectAlias("mariadb", MySqlDialect.class);
        registerDialectAlias("sqlite", MySqlDialect.class);
        registerDialectAlias("oracle", EasyMsOracleDialect.class);
        registerDialectAlias("db2", Db2Dialect.class);
        registerDialectAlias("informix", InformixDialect.class);
        registerDialectAlias("informix-sqli", InformixDialect.class);
        registerDialectAlias("sqlserver", SqlServerDialect.class);
        registerDialectAlias("sqlserver2012", SqlServer2012Dialect.class);
        registerDialectAlias("derby", SqlServer2012Dialect.class);
        registerDialectAlias("dm", EasyMsOracleDialect.class);
        registerDialectAlias("edb", EasyMsOracleDialect.class);
    }

    private Properties properties;

    private Map<String, AbstractHelperDialect> urlDialectMap = new ConcurrentHashMap<>();

    private ThreadLocal<AbstractHelperDialect> dialectThreadLocal = new ThreadLocal<>();

    EasyMsPageAutoDialect(Properties properties) {
        this.properties = properties;
    }

    void initDelegateDialect(EasyMsDataSource easyMsDataSource) {
        dialectThreadLocal.set(getDialect(easyMsDataSource));
    }

    /**
     * 获取当前的代理对象
     */
    AbstractHelperDialect getDelegate() {
        return dialectThreadLocal.get();
    }

    /**
     * 移除代理对象
     */
    void clearDelegate() {
        dialectThreadLocal.remove();
    }

    private AbstractHelperDialect getDialect(EasyMsDataSource easyMsDataSource) {
        return urlDialectMap.computeIfAbsent(easyMsDataSource.getAbbrUrl(), this::initDialect);
    }

    private Class<? extends Dialect> fromJdbcUrl(String jdbcUrl) {
        for (Map.Entry<String, Class<? extends Dialect>> entry : dialectAliasMap.entrySet()) {
            if (jdbcUrl.contains(EasyMsDataSourceConstant.CONNECT_URL_COLON_SIGN + entry.getKey() + EasyMsDataSourceConstant.CONNECT_URL_COLON_SIGN)) {
                return entry.getValue();
            }
        }
        throw new PageHelperException("无法通过url({})自动获取数据库类型!", jdbcUrl);
    }

    private AbstractHelperDialect initDialect(String jdbcUrl) {
        Class<? extends Dialect> sqlDialectClass = fromJdbcUrl(jdbcUrl);
        try {
            if (AbstractHelperDialect.class.isAssignableFrom(sqlDialectClass)) {
                AbstractHelperDialect dialect = (AbstractHelperDialect) sqlDialectClass.newInstance();
                dialect.setProperties(properties);
                return dialect;
            } else {
                throw new PageHelperException("使用 PageHelper 时，方言必须是实现{}接口的实现类!", AbstractHelperDialect.class.getCanonicalName());
            }
        } catch (Exception e) {
            throw new PageHelperException("初始化 helper [{}]时出错!", sqlDialectClass.getName(), e);
        }
    }

}